package pers.xiaojun.boot.module.system.controller.oauth2;

import cn.hutool.core.codec.Base64;
import cn.hutool.core.net.url.UrlBuilder;
import cn.hutool.core.util.StrUtil;
import com.google.common.collect.Lists;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.Parameters;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.annotation.security.PermitAll;
import jakarta.servlet.http.HttpServletRequest;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import pers.xiaojun.boot.common.exception.BusinessException;
import pers.xiaojun.boot.common.pojo.CommonResult;
import pers.xiaojun.boot.module.system.controller.oauth2.vo.OAuth2OpenAccessTokenRespVO;
import pers.xiaojun.boot.module.system.convert.OAuth2OpenConvert;
import pers.xiaojun.boot.module.system.enums.oauth2.OAuth2GrantTypeEnum;
import pers.xiaojun.boot.module.system.service.oauth2.OAuth2GrantService;
import pers.xiaojun.boot.module.system.service.oauth2.dto.OAuth2CodeDTO;
import pers.xiaojun.boot.module.system.service.oauth2.dto.OAuth2TokenDTO;
import pers.xiaojun.boot.web.core.util.WebUtils;

import java.util.ArrayList;

import static pers.xiaojun.boot.module.system.constants.BusinessCodeConstants.OAUTH2_AUTHORIZED_GRANT_TYPE_INVALID;
import static pers.xiaojun.boot.module.system.constants.BusinessCodeConstants.OAUTH2_CLIENT_OR_SECRET_INVALID;

/**
 * OAuth 2 获取授权接口
 *
 * @author xiaojun
 * @since 2025-10-18
 */
@Tag(name = "OAuth 2.0 授权")
@RequiredArgsConstructor
@RestController
@RequestMapping("/system/oauth2")
public class OAuth2OpenController {

    private final OAuth2GrantService oAuth2GrantService;

    @PostMapping("/authorize")
    @Operation(summary = "授权授权接口")
    @Parameters({
            @Parameter(name = "clientId", required = true, description = "客户端Id", example = "xiaojun-memo"),
            @Parameter(name = "responseType", required = true, description = "响应类型", example = "code"),
            @Parameter(name = "scopes", description = "授权范围", example = "user_public:read"),
            @Parameter(name = "redirectUri", required = true, description = "重定向Uri", example = "http://127.0.0.1:8080"),
            @Parameter(name = "state", required = true, description = "状态码", example = "HJGkjgkjhGKJHGjgkjhgjhGKH"),
    })
    public CommonResult<String> authorize(
            @RequestParam("clientId") String clientId,
            @RequestParam("responseType") String responseType,
            @RequestParam(value = "scopes") String scopes,
            @RequestParam(value = "redirectUri") String redirectUri,
            @RequestParam(value = "state") String state

    ) {
        // 转换响应类型
        OAuth2GrantTypeEnum grantType = OAuth2GrantTypeEnum.getByGrantType(responseType);
        if (grantType == null) {
            throw new BusinessException(OAUTH2_AUTHORIZED_GRANT_TYPE_INVALID);
        }
        //
        ArrayList<String> scopesList = Lists.newArrayList(scopes.split(","));

        // 授权码方式
        if (grantType.equals(OAuth2GrantTypeEnum.CODE)) {
            OAuth2CodeDTO oAuth2Code = oAuth2GrantService.grantAuthorizationCode(clientId, responseType, scopesList, redirectUri, state);
            return CommonResult.success(UrlBuilder
                    .of(oAuth2Code.getRedirectUri())
                    .addQuery("code", oAuth2Code.getCode())
                    .addQuery("state", oAuth2Code.getState())
                    .build()
            );
        }

        return null;
    }


    @Operation(summary = "获取访问令牌接口")
    @PostMapping("/token")
    @PermitAll
    @Parameters({
            @Parameter(name = "grantType", required = true, description = "授权类型", example = "code"),
            @Parameter(name = "code", description = "授权码", example = "code"),
            @Parameter(name = "refreshToken", description = "刷新令牌", example = "2a5144f95c504c8998b1aa696b7e70a1"),
    })
    public CommonResult<OAuth2OpenAccessTokenRespVO> token(
            HttpServletRequest request,
            @RequestParam("grantType") String grantType,
            @RequestParam(value = "code", required = false) String code,
            @RequestParam(value = "refreshToken", required = false) String refreshToken
    ) {
        // 转换响应类型
        OAuth2GrantTypeEnum grantType0 = OAuth2GrantTypeEnum.getByGrantType(grantType);
        if (grantType == null) {
            throw new BusinessException(OAUTH2_AUTHORIZED_GRANT_TYPE_INVALID);
        }
        String[] clientAuth = extractClientAuth(request);
        if (clientAuth == null) {
            throw new BusinessException(OAUTH2_CLIENT_OR_SECRET_INVALID);
        }
        OAuth2TokenDTO oAuth2Token = null;
        switch (grantType0) {
            case CODE ->
                    oAuth2Token = oAuth2GrantService.grantTokenByAuthorizationCode(clientAuth[0], clientAuth[1], code);
            case REFRESH_TOKEN ->
                    oAuth2Token = oAuth2GrantService.grantTokenByRefreshToken(refreshToken, clientAuth[0]);
        }

        return CommonResult.success(OAuth2OpenConvert.INSTANCE.toOpenToken(oAuth2Token));
    }

    /**
     * 提取 Authorization 中的客户端Id与密钥
     *
     * @return [客户端Id, 密钥]
     */
    private String[] extractClientAuth(HttpServletRequest request) {
        // 提取请求头 Authorization 中 Basic 后的内容
        String authorization = WebUtils.getAuthorization(request);
        if (StrUtil.isEmpty(authorization)) {
            return null;
        }
        // Base64解析
        authorization = Base64.decodeStr(authorization);
        // 通过 : 分割为数组
        String[] clientAuth = authorization.split(StrUtil.COLON);
        // 不等于2表示无效
        if (clientAuth.length != 2) {
            return null;
        }
        return clientAuth;
    }

}
